package com.lipaluma.util;

import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;

public class FormatterUtils {
	private enum TypeEnum {
		STRING {
			@Override
			public String format(Object value, String pattern) {
				return (String)value;
			}
		}, LONG {
			@Override
			public String format(Object value, String pattern) {
				return formatNumeric((Long)value, pattern);
			}
		}, INTEGER {
			@Override
			public String format(Object value, String pattern) {
				return formatNumeric(new Long((Integer)value), pattern);
			}
		}, INT {
			@Override
			public String format(Object value, String pattern) {
				return formatNumeric(new Long((Integer)value), pattern);
			}
	
		}, SHORT {
			@Override
			public String format(Object value, String pattern) {
				return formatNumeric(new Long((Short)value), pattern);
			}
		}, DOUBLE {
			@Override
			public String format(Object value, String pattern) {
				return formatNumeric((Double)value, pattern);
			}
		}, FLOAT {
			@Override
			public String format(Object value, String pattern) {
				return formatNumeric(new Double((Float)value), pattern);
			}
		}, BOOLEAN {
			@Override
			public String format(Object value, String pattern) {
				return BooleanUtils.toStringTrueFalse((Boolean)value);
			}
		}, DATE {
			@Override
			public String format(Object value, String pattern) {
				SimpleDateFormat fmt = new SimpleDateFormat(pattern);
				return fmt.format((Date) value);
			}
		}, DATETIME {
			@Override
			public String format(Object value, String pattern) {
				return ((DateTime)value).toString(pattern);
			}
		};
	
		private static String formatNumeric(Long value, String pattern) {
			if(StringUtils.isNotBlank(pattern)) {
				DecimalFormat format = new DecimalFormat(pattern);
				return format.format(value).toString();
			}
			return value.toString();
		}
	
		private static String formatNumeric(Double value, String pattern) {
			if(StringUtils.isNotBlank(pattern)) {
				DecimalFormat format = new DecimalFormat(pattern);
				return format.format(value).toString();
			}
			return value.toString();
		}

		public abstract String format(Object value, String pattern);
	}

	/**
	 * format the value to String
	 * @param value the value to format
	 * @return the value formatted
	 */
	public static String formatFromType(Object value) {
		return formatFromType(value, null);
	}

	/**
	 * format the value with the given pattern if is not null
	 * @param value the value to format
	 * @param pattern can be null, pattern of the value
	 * @return the value formatted
	 */
	public static String formatFromType(Object value, String pattern) {
		TypeEnum formatByType = TypeEnum.valueOf(value.getClass().getSimpleName().toUpperCase());
		return formatByType.format(value, pattern);
	}
	
	/**
	 * format the enum value
	 * @param enum value to format
	 * @return value formatted
	 */
	public static String formatFromEnum(Object value) {
		Method method = ReflectionUtils.findMethod(value.getClass(), "name");
		ReflectionUtils.makeAccessible(method);
		return ReflectionUtils.invokeMethod(method, value).toString();
	}

	/**
	 * Format the enum or other type value
	 * @param value the value to format
	 * @param pattern pattern of the format
	 * @return the value formatted
	 */
	public static String formatFromTypeOrEnum(Object value, String pattern) {
		if (value.getClass().isEnum()) {
			return formatFromEnum(value);
		} else { 
			return formatFromType(value, pattern);
		}
	}

}
